package com.copractice.data.entity.question;

import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.JoinColumn;
import javax.persistence.Table;

import com.copractice.data.entity.PersistentObject;
import com.copractice.data.entity.answer.Answer;
import com.copractice.data.entity.feedback.UsersFeedback;
import com.copractice.data.entity.tag.Tag;
import com.copractice.data.entity.user.User;

/**
 * Represents question entity.
 *
 * @author Dmitry Churbanov (dmitry.churbanov@gmail.com)
 * @version 1.0 03/14/2009
 */
@Entity
@Table(name = "QUESTIONS")
@NamedQueries(
{   @NamedQuery(name = "QUESTIONS.findByTagId", 
                query = "select q from Question q left join q.tags qt where qt.id = ?"
               ),
    @NamedQuery(name = "QUESTIONS.findByTagIdSort", 
                query = "select q from Question q left join q.tags qt where qt.id = ? order by " +
                        "((q.intelDiff * q.numberOfUserAttempts) + (q.userDiff * q.numberOfUserRating))/" +
                        "(q.numberOfUserAttempts + q.numberOfUserRating) asc, q.discrimination desc"
                ),
    @NamedQuery(name = "QUESTIONS.findById",
                query = "select q from Question q where q.id = ?"
                )
})
@SuppressWarnings("serial")
public class Question extends PersistentObject {

    /**
     * Questions name
     */
    private String name;

    /**
     * Questions condition
     */
    private String condition;

    /**
     * Questions difficulty by the intelligence of the application
     */
    private Long intelDiff;

    /**
     * Questions difficulty as rated by the user
     */
    private Long userDiff;
    
    private Long numberOfUserAttempts;
    
    private Long numberOfUserRating;
    
    /**
     * Questions discrimination -1 to +1
     */
    private Double discrimination;

    /**
     * Date of questions creation
     */
    private Date createdDate;

    /**
     * Questions type
     */
    private QuestionType type;

    /**
     * User who created current question
     */
    private User created;

    /**
     * Answers of this question
     */
    private List<Answer> answers;

    /**
     * Tags of current question
     */
    private List<Tag> tags; 
    
    /**
     * Feedback for current question
     */
    private List<UsersFeedback> feedback;
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Override
    public Long getId() {
        return super.getId();
    }
    
    /**
     * Gets questions name
     *
     * @return users name
     */
    @Column(name = "NAME")
    public String getName() {
        return name;
    }

    /**
     * Sets questions name
     *
     * @param name users name to set
     */
    public void setName(String name) {
        this.name = name;
    }
    
    /**
     * Gets questions condition
     *
     * @return questions condition
     */
    @Column(name = "QCONDITION")
    public String getCondition() {
        return condition;
    }

    /**
     * Sets questions condition
     *
     * @param condition questions condition to set
     */
    public void setCondition(String condition) {
        this.condition = condition;
    }
    
    /**
     * Gets questions difficulty by the intelligence of the application
     *  
     * @return questions difficulty by the intelligence of the application
     */
    @Column(name = "INTEL_DIFF")
    public Long getIntelDiff() {
        return intelDiff;
    }

    /**
     * Sets questions difficulty by the intelligence of the application
     *  
     * @param intelDiff questions difficulty by the intelligence of the application
     */
    public void setIntelDiff(Long intelDiff) {
        this.intelDiff = intelDiff;
    }    
    
    @Column(name = "USER_DIFF")
    public Long getUserDiff() {
        return userDiff;
    }

    public void setUserDiff(Long userDiff) {
        this.userDiff = userDiff;
    } 
    
    @Column(name = "NUM_USER_ATTEMPTS")
    public Long getNumberOfUserAttempts() {
        return numberOfUserAttempts;
    }

    public void setNumberOfUserAttempts(Long numberOfUserAttempts) {
        this.numberOfUserAttempts = numberOfUserAttempts;
    }

    @Column(name = "NUM_USER_RATING")
    public Long getNumberOfUserRating() {
        return numberOfUserRating;
    }

    public void setNumberOfUserRating(Long numberOfUserRating) {
        this.numberOfUserRating = numberOfUserRating;
    }
    
    @Column(name = "DISCRIMINATION")
    public Double getDiscrimination() {
        return discrimination;
    }

    public void setDiscrimination(Double discrimination) {
        this.discrimination = discrimination;
    }
    
    /**
     * Gets questions creation date
     *
     * @return date when question was created
     */
    @Column(name = "CREATED_DATE")
    public Date getCreatedDate() {
        return createdDate;
    }

    /**
     * Sets questions creation date
     *
     * @param createdDate questions creation date
     */
    public void setCreatedDate(Date createdDate) {
        this.createdDate = createdDate;
    }
    
    /**
     * Type of a question
     *
     * @return type of a question
     */
    @Column(name = "QUESTION_TYPE")
    public QuestionType getType() {
        return type;
    }

    /**
     * Sets type of a question
     *
     * @param type type of a question
     */
    public void setType(QuestionType type) {
        this.type = type;
    }    
    
    /**
     * Gets user who created this question
     *
     * @return user who created this question
     */
    @ManyToOne
    @JoinColumn(name="CREATED_ID")
    public User getCreated() {
        return created;
    }

    /**
     * Sets user who created this question
     *
     * @param created  user who created this question
     */
    public void setCreated(User created) {
        this.created = created;
    }
    
    /**
     * Returns answers of this question
     *
     * @return collection of <code>Answer</code> of this question
     */
    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "question")
    public List<Answer> getAnswers() {
        return answers;
    }

    /**
     * Sets answers of this question
     *
     * @param answers collection of <code>Answers</code> of this question
     */
    public void setAnswers(List<Answer> answers) {
        this.answers = answers;
    }
    
    /**
     * Returns tags of the question
     *
     * @return the <code>List</code> of tags this question has
     */
    @ManyToMany
    @JoinTable(name="QUESTIONS_TAGS")
    public List<Tag> getTags() {
        return tags;
    }

    /**
     * Sets tags of the question
     *
     * @param tags the <code>List</code> of tags this question has
     */
    public void setTags(List<Tag> tags) {
        this.tags = tags;
    }

    /**
     * Returns feedbacks for this question
     * 
     * @return collection of <code>UsersFeedback</code> of this question
     */
    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "question")
    public List<UsersFeedback> getFeedback() {
        return feedback;
    }

    /**
     * Sets feedback of this question
     * 
     * @param feedback collection of <code>UsersFeedback</code> of this question
     */
    public void setFeedback(List<UsersFeedback> feedback) {
        this.feedback = feedback;
    }    
    
}
